#include "ota_version.h"
#define CUR_VER "{\"major\": 1, \"min\": 0, \"patch\": 0}"
#define OTA_VERSION_INFO_URL "http://192.168.55.88:8000/ota_server/version.json"
#define OTA_GATE_SW_URL "http://192.168.55.88:8000/ota_server/gateway"
#define OTA_GATE_SW_PATH "/usr/bin/gateway.update"

typedef struct
{
    int major;
    int min;
    int patch;
    char *sha1;
} version_t;

void ota_version_parse_version_json(char *json, version_t *version)
{
    cJSON *root = cJSON_Parse(json);

    version->major = cJSON_GetObjectItem(root, "major")->valueint;
    version->min = cJSON_GetObjectItem(root, "min")->valueint;
    version->patch = cJSON_GetObjectItem(root, "patch")->valueint;

    cJSON *sha1Item = cJSON_GetObjectItem(root, "sha1");
    if (sha1Item != NULL)
    {
        version->sha1 = strdup(cJSON_GetStringValue(sha1Item));
    }

    cJSON_Delete(root);
}

/**
 * 获取文件的SHA1哈希值（40位16进制字符串）
 * 相同文件返回相同的哈希值，可用于判断文件是否相同
 * linux命令生成：sha1sum 文件名
 * 此函数可以利用AI工具帮我们生成
 */
static char *get_file_sha(char *filepath)
{
    FILE *file = fopen(filepath, "rb");
    if (!file)
    {
        perror("Failed to open file");
        return NULL;
    }

    unsigned char hash[SHA_DIGEST_LENGTH];
    SHA_CTX sha1;
    SHA1_Init(&sha1);

    const int bufSize = 32768;
    unsigned char *buffer = (unsigned char *)malloc(bufSize);
    if (!buffer)
    {
        perror("Failed to allocate memory");
        fclose(file);
        return NULL;
    }

    int bytesRead;
    while ((bytesRead = fread(buffer, 1, bufSize, file)) > 0)
    {
        SHA1_Update(&sha1, buffer, bytesRead);
    }

    SHA1_Final(hash, &sha1);
    fclose(file);
    free(buffer);

    char *outputBuffer = (char *)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!outputBuffer)
    {
        perror("Failed to allocate memory");
        return NULL;
    }

    for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
    {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }

    return outputBuffer;
}

gate_status_t ota_version_check(void)
{
    version_t newVer;
    version_t curVer;

    char *version_info_json = ota_http_getText(OTA_VERSION_INFO_URL);

    ota_version_parse_version_json(version_info_json, &newVer);
    ota_version_parse_version_json(CUR_VER, &curVer);

    // 打印 newVer和curVer
    printf("newVer: %d.%d.%d %s\n", newVer.major, newVer.min, newVer.patch, newVer.sha1);
    printf("curVer: %d.%d.%d\n", curVer.major, curVer.min, curVer.patch);

    if (newVer.major < curVer.major ||
        (newVer.major == curVer.major && newVer.min < curVer.min) ||
        (newVer.major == curVer.major && newVer.min == curVer.min && newVer.patch <= curVer.patch))
    {
        printf("当前版本已经是最新版本\n");
        return GATE_OK;
    }
    // 需要更新
    log_info("需要更新\n");
    gate_status_t status = ota_http_download(OTA_GATE_SW_URL, OTA_GATE_SW_PATH);
    if (status != GATE_OK)
    {
        log_error("下载失败\n");
        return status;
    }
    // 更新成功
    log_info("开始做哈希校验");

    // 给下载的文件做哈希,然后和服务器提供的哈希值做比较
    char *newSha1 = newVer.sha1;
    char *localSha1 = get_file_sha(OTA_GATE_SW_PATH);
    if (strcmp(newSha1, localSha1) != 0)
    {
        log_error("哈希校验失败\n");
        return GATE_ERROR;
    }
    log_info("哈希校验成功\n");
    log_info("下载成功\n");

    free(version_info_json);
    free(localSha1);

    // 重启系统, 会有自启动脚本,检测是否有 gateway.update, 如果有,则改名为gateway, 然后启动
    reboot(RB_AUTOBOOT);
    return GATE_OK;
}

void ota_version_auto_update(void)
{
    ota_version_check();

    while (1)
    {
        // 当前时间戳
        time_t now = time(NULL);

        struct tm *t = localtime(&now);

        if (t->tm_hour == 11 && t->tm_min == 32)
        {
            ota_version_check();
        }
        sleep(60);
    }
}
